"""
Python MCP server implementation.

Provides Python-specific code analysis tools for function call tree generation
and code understanding through AST parsing and analysis.
"""

import ast
import inspect
import importlib.util
from typing import Dict, List, Any, Optional, Union
from pathlib import Path

from ...core.base_mcp import BaseMCP
from ...core.error_handler import CodeMCPError, AnalysisError, log_info
from ...core.entry_discovery import EntryPointDiscovery, EntryDiscoveryConfig
from ...core.project_scanner import ProjectScanner, ProjectScanConfig
from ...core.function_classifier import FunctionClassifier, ClassificationConfig
from ...core.cross_file_resolver import CrossFileResolver
from .parser import PythonParser
from .analyzer import CallGraphAnalyzer
from .resolver import ImportResolver
from .decorators import DecoratorAnalyzer
from .typing_utils import TypeAnalyzer
from .dynamic_calls import DynamicCallDetector


class PythonMCP(BaseMCP):
    """Python-specific MCP server for code analysis."""
    
    def __init__(self, config=None):
        """Initialize Python MCP server."""
        super().__init__(name="python_mcp", language="python", config=config)
        
        # Initialize analyzers
        self.parser = PythonParser()
        self.call_analyzer = CallGraphAnalyzer()
        self.import_resolver = ImportResolver()
        self.decorator_analyzer = DecoratorAnalyzer()
        self.type_analyzer = TypeAnalyzer()
        self.dynamic_detector = DynamicCallDetector()
        
        # Initialize discovery components
        discovery_config = EntryDiscoveryConfig(
            languages=['python'],
            ignore_tests=True,
            ignore_examples=True,
            min_confidence=0.7
        )
        self.entry_discovery = EntryPointDiscovery(discovery_config)
        
        scan_config = ProjectScanConfig(
            language_filters=['python'],
            include_build_files=True,
            max_depth=10
        )
        self.project_scanner = ProjectScanner(scan_config)
        
        classification_config = ClassificationConfig(
            language='python',
            min_confidence=0.6
        )
        self.function_classifier = FunctionClassifier(classification_config)
        
        self.cross_file_resolver = CrossFileResolver()
        
        # Register Python-specific tools
        self._register_tools()
    
    async def _register_default_tools(self):
        """Register default tools for this MCP server."""
        # This is now handled by _register_tools()
        pass
    
    async def _initialize_language_components(self):
        """Initialize language-specific components."""
        # Components are already initialized in __init__
        pass
    
    def _is_supported_file(self, file_path: Path) -> bool:
        """Check if file is supported by this MCP server."""
        return file_path.suffix in self.get_supported_extensions()
    
    def _get_supported_extensions(self) -> List[str]:
        """Get list of supported file extensions."""
        return ['.py', '.pyi', '.pyx']
    
    async def parse_file(self, file_path: str) -> Any:
        """Parse a file and return AST or equivalent structure."""
        file_path = Path(file_path)
        if not file_path.exists():
            raise AnalysisError(f"File not found: {file_path}")
        
        with open(file_path, 'r', encoding='utf-8') as f:
            source_code = f.read()
        
        try:
            ast_tree = ast.parse(source_code, filename=str(file_path))
            return self.parser.parse_file(ast_tree, str(file_path))
        except SyntaxError as e:
            raise AnalysisError(f"Syntax error in {file_path}: {e}")
    
    async def build_call_tree(self, entry_point: str, max_depth: int = None) -> Any:
        """Build a call tree from an entry point."""
        # This is a simplified implementation - in practice would integrate with storage
        from ...core.base_mcp import CallTree, CallTreeNode
        
        # For now, return a simple tree structure
        root_node = CallTreeNode(
            name=entry_point,
            file_path="unknown",
            line_number=1,
            language="python"
        )
        
        tree = CallTree(root_node)
        return tree
    
    async def _extract_function_info(self, ast_data: Any, function_name: str) -> Optional[Dict[str, Any]]:
        """Extract function information from AST data."""
        if not isinstance(ast_data, dict) or 'functions' not in ast_data:
            return None
        
        for func in ast_data['functions']:
            if func['name'] == function_name:
                return func
        
        return None
    
    async def _extract_dependencies(self, ast_data: Any) -> List[Dict[str, Any]]:
        """Extract dependencies from AST data."""
        if not isinstance(ast_data, dict) or 'imports' not in ast_data:
            return []
        
        return ast_data['imports']
    
    def register_tool(self, name: str, description: str, parameters: dict, handler: callable):
        """Register a tool with the MCP server."""
        # For now, just store tools in a simple list - would integrate with tool registry in full implementation
        if not hasattr(self, 'tools'):
            self.tools = []
        
        self.tools.append({
            'name': name,
            'description': description,
            'parameters': parameters,
            'handler': handler
        })
    
    def _register_tools(self):
        """Register Python analysis tools."""
        self.register_tool(
            name="analyze_file",
            description="Analyze a Python file for function calls and structure",
            parameters={
                "type": "object",
                "properties": {
                    "file_path": {
                        "type": "string",
                        "description": "Path to the Python file to analyze"
                    },
                    "include_imports": {
                        "type": "boolean",
                        "description": "Whether to resolve and include imports",
                        "default": True
                    },
                    "include_decorators": {
                        "type": "boolean", 
                        "description": "Whether to analyze decorator effects",
                        "default": True
                    },
                    "detect_dynamic": {
                        "type": "boolean",
                        "description": "Whether to detect dynamic calls",
                        "default": True
                    }
                },
                "required": ["file_path"]
            },
            handler=self._analyze_file
        )
        
        self.register_tool(
            name="analyze_function",
            description="Analyze a specific function in a Python file",
            parameters={
                "type": "object",
                "properties": {
                    "file_path": {
                        "type": "string",
                        "description": "Path to the Python file"
                    },
                    "function_name": {
                        "type": "string",
                        "description": "Name of the function to analyze"
                    },
                    "max_depth": {
                        "type": "integer",
                        "description": "Maximum call tree depth to explore",
                        "default": 10
                    }
                },
                "required": ["file_path", "function_name"]
            },
            handler=self._analyze_function
        )
        
        self.register_tool(
            name="get_call_tree",
            description="Generate complete call tree for a Python function",
            parameters={
                "type": "object",
                "properties": {
                    "file_path": {
                        "type": "string",
                        "description": "Path to the Python file"
                    },
                    "function_name": {
                        "type": "string",
                        "description": "Starting function name"
                    },
                    "max_depth": {
                        "type": "integer",
                        "description": "Maximum tree depth",
                        "default": 10
                    },
                    "include_external": {
                        "type": "boolean",
                        "description": "Include calls to external modules",
                        "default": False
                    }
                },
                "required": ["file_path", "function_name"]
            },
            handler=self._get_call_tree
        )
        
        self.register_tool(
            name="analyze_imports",
            description="Analyze import dependencies in a Python file",
            parameters={
                "type": "object",
                "properties": {
                    "file_path": {
                        "type": "string",
                        "description": "Path to the Python file"
                    },
                    "resolve_modules": {
                        "type": "boolean",
                        "description": "Whether to resolve module paths",
                        "default": True
                    }
                },
                "required": ["file_path"]
            },
            handler=self._analyze_imports
        )
        
        self.register_tool(
            name="analyze_class",
            description="Analyze a Python class and its methods",
            parameters={
                "type": "object",
                "properties": {
                    "file_path": {
                        "type": "string",
                        "description": "Path to the Python file"
                    },
                    "class_name": {
                        "type": "string",
                        "description": "Name of the class to analyze"
                    },
                    "include_inheritance": {
                        "type": "boolean",
                        "description": "Include inheritance hierarchy analysis",
                        "default": True
                    }
                },
                "required": ["file_path", "class_name"]
            },
            handler=self._analyze_class
        )
        
        # Project-wide discovery tools
        self.register_tool(
            name="discover_project",
            description="Discover Python project structure and entry points",
            parameters={
                "type": "object",
                "properties": {
                    "project_path": {
                        "type": "string",
                        "description": "Path to the project root directory"
                    },
                    "include_entry_points": {
                        "type": "boolean",
                        "description": "Whether to discover entry points",
                        "default": True
                    },
                    "classify_functions": {
                        "type": "boolean",
                        "description": "Whether to classify functions",
                        "default": True
                    }
                },
                "required": ["project_path"]
            },
            handler=self._discover_project
        )
        
        self.register_tool(
            name="find_entry_points",
            description="Find all entry points in a Python project",
            parameters={
                "type": "object",
                "properties": {
                    "project_path": {
                        "type": "string",
                        "description": "Path to the project root directory"
                    },
                    "entry_types": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Types of entry points to find (main, cli, export)",
                        "default": ["main", "cli"]
                    }
                },
                "required": ["project_path"]
            },
            handler=self._find_entry_points
        )
        
        self.register_tool(
            name="classify_project_functions",
            description="Classify all functions in a Python project",
            parameters={
                "type": "object",
                "properties": {
                    "project_path": {
                        "type": "string",
                        "description": "Path to the project root directory"
                    },
                    "include_test_files": {
                        "type": "boolean",
                        "description": "Whether to include test files",
                        "default": False
                    }
                },
                "required": ["project_path"]
            },
            handler=self._classify_project_functions
        )
        
        self.register_tool(
            name="resolve_cross_file_dependencies",
            description="Resolve dependencies and calls across Python files",
            parameters={
                "type": "object",
                "properties": {
                    "project_path": {
                        "type": "string",
                        "description": "Path to the project root directory"
                    },
                    "target_files": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Specific files to analyze (optional)"
                    }
                },
                "required": ["project_path"]
            },
            handler=self._resolve_cross_file_dependencies
        )
        
        self.register_tool(
            name="analyze_project_tree",
            description="Generate comprehensive call tree for entire Python project",
            parameters={
                "type": "object",
                "properties": {
                    "project_path": {
                        "type": "string",
                        "description": "Path to the project root directory"
                    },
                    "entry_point": {
                        "type": "string",
                        "description": "Starting entry point (optional - auto-discovered if not provided)"
                    },
                    "max_depth": {
                        "type": "integer",
                        "description": "Maximum tree depth",
                        "default": 15
                    },
                    "include_external": {
                        "type": "boolean",
                        "description": "Include external package calls",
                        "default": False
                    }
                },
                "required": ["project_path"]
            },
            handler=self._analyze_project_tree
        )
    
    async def _analyze_file(self, file_path: str, include_imports: bool = True, 
                           include_decorators: bool = True, detect_dynamic: bool = True) -> Dict[str, Any]:
        """Analyze a Python file for structure and calls."""
        try:
            file_path = Path(file_path)
            if not file_path.exists():
                raise AnalysisError(f"File not found: {file_path}")
            
            log_info(f"Analyzing Python file: {file_path}")
            
            # Parse the file
            with open(file_path, 'r', encoding='utf-8') as f:
                source_code = f.read()
            
            # Parse AST
            try:
                ast_tree = ast.parse(source_code, filename=str(file_path))
            except SyntaxError as e:
                raise AnalysisError(f"Syntax error in {file_path}: {e}")
            
            # Perform analysis
            analysis_result = self.parser.parse_file(ast_tree, str(file_path))
            
            # Add import analysis if requested
            if include_imports:
                imports = await self._analyze_imports(str(file_path))
                analysis_result['imports'] = imports['imports']
                analysis_result['import_graph'] = imports['import_graph']
            
            # Add decorator analysis if requested
            if include_decorators:
                decorators = self.decorator_analyzer.analyze_decorators(ast_tree)
                analysis_result['decorators'] = decorators
            
            # Add dynamic call detection if requested
            if detect_dynamic:
                dynamic_calls = self.dynamic_detector.detect_dynamic_calls(ast_tree)
                analysis_result['dynamic_calls'] = dynamic_calls
            
            # Add type analysis
            type_info = self.type_analyzer.analyze_types(ast_tree)
            analysis_result['type_info'] = type_info
            
            return {
                'status': 'success',
                'file_path': str(file_path),
                'analysis': analysis_result,
                'metadata': {
                    'lines_of_code': len(source_code.splitlines()),
                    'ast_nodes': len(list(ast.walk(ast_tree))),
                    'functions': len(analysis_result.get('functions', [])),
                    'classes': len(analysis_result.get('classes', [])),
                    'imports': len(analysis_result.get('imports', []))
                }
            }
            
        except Exception as e:
            log_info(f"Error analyzing file {file_path}: {e}")
            raise AnalysisError(f"Failed to analyze file: {e}")
    
    async def _analyze_function(self, file_path: str, function_name: str, max_depth: int = 10) -> Dict[str, Any]:
        """Analyze a specific function in a Python file."""
        try:
            file_analysis = await self._analyze_file(file_path)
            analysis = file_analysis['analysis']
            
            # Find the target function
            target_function = None
            for func in analysis.get('functions', []):
                if func['name'] == function_name:
                    target_function = func
                    break
            
            if not target_function:
                raise AnalysisError(f"Function '{function_name}' not found in {file_path}")
            
            # Generate call graph for this function
            call_graph = self.call_analyzer.analyze_function_calls(
                target_function, analysis, max_depth
            )
            
            return {
                'status': 'success',
                'file_path': file_path,
                'function_name': function_name,
                'function_info': target_function,
                'call_graph': call_graph,
                'metadata': {
                    'max_depth_reached': call_graph.get('max_depth', 0),
                    'total_calls': call_graph.get('total_calls', 0),
                    'unique_functions': len(call_graph.get('unique_functions', set()))
                }
            }
            
        except Exception as e:
            log_info(f"Error analyzing function {function_name} in {file_path}: {e}")
            raise AnalysisError(f"Failed to analyze function: {e}")
    
    async def _get_call_tree(self, file_path: str, function_name: str, max_depth: int = 10, 
                            include_external: bool = False) -> Dict[str, Any]:
        """Generate complete call tree for a Python function."""
        try:
            # First analyze the function
            func_analysis = await self._analyze_function(file_path, function_name, max_depth)
            
            # Build the call tree structure
            call_tree = self.call_analyzer.build_call_tree(
                func_analysis['call_graph'],
                include_external=include_external
            )
            
            return {
                'status': 'success',
                'file_path': file_path,
                'root_function': function_name,
                'call_tree': call_tree,
                'statistics': {
                    'total_nodes': call_tree.get('statistics', {}).get('node_count', 1),
                    'max_depth': call_tree.get('statistics', {}).get('max_depth', 1),
                    'external_calls': call_tree.get('statistics', {}).get('external_calls', 0),
                    'recursive_calls': call_tree.get('statistics', {}).get('recursive_calls', 0)
                }
            }
            
        except Exception as e:
            log_info(f"Error generating call tree for {function_name}: {e}")
            raise AnalysisError(f"Failed to generate call tree: {e}")
    
    async def _analyze_imports(self, file_path: str, resolve_modules: bool = True) -> Dict[str, Any]:
        """Analyze import dependencies in a Python file."""
        try:
            file_path = Path(file_path)
            
            with open(file_path, 'r', encoding='utf-8') as f:
                source_code = f.read()
            
            ast_tree = ast.parse(source_code, filename=str(file_path))
            
            # Extract imports
            imports = self.import_resolver.extract_imports(ast_tree)
            
            # Resolve module paths if requested
            if resolve_modules:
                resolved_imports = self.import_resolver.resolve_imports(
                    imports, file_path.parent
                )
                import_graph = self.import_resolver.build_dependency_graph(
                    resolved_imports
                )
            else:
                resolved_imports = imports
                import_graph = {}
            
            return {
                'status': 'success',
                'file_path': str(file_path),
                'imports': resolved_imports,
                'import_graph': import_graph,
                'statistics': {
                    'total_imports': len(imports),
                    'standard_library': len([i for i in imports if i.get('is_stdlib', False)]),
                    'third_party': len([i for i in imports if i.get('is_third_party', False)]),
                    'local_modules': len([i for i in imports if i.get('is_local', False)])
                }
            }
            
        except Exception as e:
            log_info(f"Error analyzing imports in {file_path}: {e}")
            raise AnalysisError(f"Failed to analyze imports: {e}")
    
    async def _analyze_class(self, file_path: str, class_name: str, 
                            include_inheritance: bool = True) -> Dict[str, Any]:
        """Analyze a Python class and its methods."""
        try:
            file_analysis = await self._analyze_file(file_path)
            analysis = file_analysis['analysis']
            
            # Find the target class
            target_class = None
            for cls in analysis.get('classes', []):
                if cls['name'] == class_name:
                    target_class = cls
                    break
            
            if not target_class:
                raise AnalysisError(f"Class '{class_name}' not found in {file_path}")
            
            result = {
                'status': 'success',
                'file_path': file_path,
                'class_name': class_name,
                'class_info': target_class,
                'methods': target_class.get('methods', []),
                'attributes': target_class.get('attributes', [])
            }
            
            # Add inheritance analysis if requested
            if include_inheritance:
                inheritance_info = self.call_analyzer.analyze_class_hierarchy(
                    target_class, analysis
                )
                result['inheritance'] = inheritance_info
            
            return result
            
        except Exception as e:
            log_info(f"Error analyzing class {class_name} in {file_path}: {e}")
            raise AnalysisError(f"Failed to analyze class: {e}")
    
    async def _discover_project(self, project_path: str, include_entry_points: bool = True, 
                               classify_functions: bool = True) -> Dict[str, Any]:
        """Discover Python project structure and entry points."""
        try:
            project_path = Path(project_path)
            if not project_path.exists():
                raise AnalysisError(f"Project path not found: {project_path}")
            
            log_info(f"Discovering Python project: {project_path}")
            
            # Scan project structure
            project_info = self.project_scanner.scan_project(project_path)
            
            result = {
                'status': 'success',
                'project_path': str(project_path),
                'project_info': project_info
            }
            
            # Discover entry points if requested
            if include_entry_points:
                entry_points = self.entry_discovery.discover_entry_points(project_path)
                result['entry_points'] = [ep.__dict__ for ep in entry_points]
            
            # Classify functions if requested
            if classify_functions:
                python_files = [f for f in project_info.get('files', []) 
                              if f.get('language') == 'python']
                
                all_classifications = []
                for file_info in python_files:
                    file_path = file_info['path']
                    try:
                        classifications = await self._classify_file_functions(file_path)
                        all_classifications.extend(classifications)
                    except Exception as e:
                        log_info(f"Failed to classify functions in {file_path}: {e}")
                
                result['function_classifications'] = all_classifications
            
            return result
            
        except Exception as e:
            log_info(f"Error discovering project {project_path}: {e}")
            raise AnalysisError(f"Failed to discover project: {e}")
    
    async def _find_entry_points(self, project_path: str, entry_types: List[str] = None) -> Dict[str, Any]:
        """Find all entry points in a Python project."""
        try:
            project_path = Path(project_path)
            if not project_path.exists():
                raise AnalysisError(f"Project path not found: {project_path}")
            
            if entry_types is None:
                entry_types = ["main", "cli"]
            
            log_info(f"Finding entry points in: {project_path}")
            
            # Discover all entry points
            all_entry_points = self.entry_discovery.discover_entry_points(project_path)
            
            # Filter by requested types
            filtered_entry_points = [
                ep for ep in all_entry_points 
                if ep.entry_type in entry_types
            ]
            
            # Group by type and file
            by_type = {}
            by_file = {}
            
            for ep in filtered_entry_points:
                if ep.entry_type not in by_type:
                    by_type[ep.entry_type] = []
                by_type[ep.entry_type].append(ep.__dict__)
                
                if ep.file_path not in by_file:
                    by_file[ep.file_path] = []
                by_file[ep.file_path].append(ep.__dict__)
            
            # Get best entry point
            best_entry_point = self.entry_discovery.get_best_entry_point(filtered_entry_points)
            
            return {
                'status': 'success',
                'project_path': str(project_path),
                'entry_points': [ep.__dict__ for ep in filtered_entry_points],
                'by_type': by_type,
                'by_file': by_file,
                'best_entry_point': best_entry_point.__dict__ if best_entry_point else None,
                'statistics': {
                    'total_found': len(filtered_entry_points),
                    'types_found': list(by_type.keys()),
                    'files_with_entries': len(by_file)
                }
            }
            
        except Exception as e:
            log_info(f"Error finding entry points in {project_path}: {e}")
            raise AnalysisError(f"Failed to find entry points: {e}")
    
    async def _classify_project_functions(self, project_path: str, include_test_files: bool = False) -> Dict[str, Any]:
        """Classify all functions in a Python project."""
        try:
            project_path = Path(project_path)
            if not project_path.exists():
                raise AnalysisError(f"Project path not found: {project_path}")
            
            log_info(f"Classifying functions in project: {project_path}")
            
            # Scan for Python files
            project_info = self.project_scanner.scan_project(project_path)
            python_files = [f for f in project_info.get('files', []) 
                          if f.get('language') == 'python']
            
            # Filter test files if not requested
            if not include_test_files:
                python_files = [f for f in python_files 
                              if not any(test_pattern in f['path'].lower() 
                                       for test_pattern in ['test_', '_test.py', 'tests/'])]
            
            all_classifications = []
            statistics = {
                'files_processed': 0,
                'functions_classified': 0,
                'classification_counts': {},
                'errors': []
            }
            
            for file_info in python_files:
                file_path = file_info['path']
                try:
                    classifications = await self._classify_file_functions(file_path)
                    all_classifications.extend(classifications)
                    statistics['files_processed'] += 1
                    statistics['functions_classified'] += len(classifications)
                    
                    # Count classification types
                    for classification in classifications:
                        func_type = classification.get('function_type', 'unknown')
                        statistics['classification_counts'][func_type] = \
                            statistics['classification_counts'].get(func_type, 0) + 1
                            
                except Exception as e:
                    error_msg = f"Failed to classify functions in {file_path}: {e}"
                    statistics['errors'].append(error_msg)
                    log_info(error_msg)
            
            return {
                'status': 'success',
                'project_path': str(project_path),
                'classifications': all_classifications,
                'statistics': statistics
            }
            
        except Exception as e:
            log_info(f"Error classifying project functions in {project_path}: {e}")
            raise AnalysisError(f"Failed to classify project functions: {e}")
    
    async def _resolve_cross_file_dependencies(self, project_path: str, target_files: List[str] = None) -> Dict[str, Any]:
        """Resolve dependencies and calls across Python files."""
        try:
            project_path = Path(project_path)
            if not project_path.exists():
                raise AnalysisError(f"Project path not found: {project_path}")
            
            log_info(f"Resolving cross-file dependencies in: {project_path}")
            
            # Get files to analyze
            if target_files:
                files_to_analyze = [project_path / f for f in target_files]
            else:
                project_info = self.project_scanner.scan_project(project_path)
                files_to_analyze = [Path(f['path']) for f in project_info.get('files', []) 
                                  if f.get('language') == 'python']
            
            # Resolve dependencies
            resolution_result = self.cross_file_resolver.resolve_dependencies(
                files_to_analyze, project_path
            )
            
            return {
                'status': 'success',
                'project_path': str(project_path),
                'resolution_result': resolution_result,
                'statistics': {
                    'files_analyzed': len(files_to_analyze),
                    'dependencies_found': len(resolution_result.get('dependencies', [])),
                    'call_relationships': len(resolution_result.get('call_graph', {})),
                    'unresolved_imports': len(resolution_result.get('unresolved', []))
                }
            }
            
        except Exception as e:
            log_info(f"Error resolving cross-file dependencies in {project_path}: {e}")
            raise AnalysisError(f"Failed to resolve cross-file dependencies: {e}")
    
    async def _analyze_project_tree(self, project_path: str, entry_point: str = None, 
                                   max_depth: int = 15, include_external: bool = False) -> Dict[str, Any]:
        """Generate comprehensive call tree for entire Python project."""
        try:
            project_path = Path(project_path)
            if not project_path.exists():
                raise AnalysisError(f"Project path not found: {project_path}")
            
            log_info(f"Analyzing project call tree: {project_path}")
            
            # Discover entry point if not provided
            if not entry_point:
                entry_points = self.entry_discovery.discover_entry_points(project_path)
                best_entry = self.entry_discovery.get_best_entry_point(entry_points)
                if not best_entry:
                    raise AnalysisError("No suitable entry point found in project")
                entry_point = f"{best_entry.file_path}:{best_entry.name}"
                log_info(f"Auto-discovered entry point: {entry_point}")
            
            # Parse entry point
            if ':' in entry_point:
                file_path, function_name = entry_point.split(':', 1)
            else:
                # Try to find main function in the file
                file_path = entry_point
                function_name = "main"  # Default assumption
            
            # First resolve cross-file dependencies
            dependency_result = await self._resolve_cross_file_dependencies(str(project_path))
            
            # Build comprehensive call tree
            call_tree_result = await self._get_call_tree(
                file_path, function_name, max_depth, include_external
            )
            
            # Enhance with cross-file information
            enhanced_tree = self._enhance_tree_with_cross_file_info(
                call_tree_result['call_tree'],
                dependency_result['resolution_result']
            )
            
            return {
                'status': 'success',
                'project_path': str(project_path),
                'entry_point': entry_point,
                'call_tree': enhanced_tree,
                'cross_file_dependencies': dependency_result['resolution_result'],
                'statistics': {
                    'total_nodes': enhanced_tree.get('statistics', {}).get('node_count', 1),
                    'max_depth': enhanced_tree.get('statistics', {}).get('max_depth', 1),
                    'cross_file_calls': enhanced_tree.get('statistics', {}).get('cross_file_calls', 0),
                    'external_calls': enhanced_tree.get('statistics', {}).get('external_calls', 0),
                    'files_involved': len(set(node.get('file_path', '') for node in 
                                           self._flatten_tree_nodes(enhanced_tree)))
                }
            }
            
        except Exception as e:
            log_info(f"Error analyzing project tree for {project_path}: {e}")
            raise AnalysisError(f"Failed to analyze project tree: {e}")
    
    async def _classify_file_functions(self, file_path: str) -> List[Dict[str, Any]]:
        """Classify functions in a single Python file."""
        file_analysis = await self._analyze_file(file_path)
        functions = file_analysis['analysis'].get('functions', [])
        
        classifications = []
        for func in functions:
            classification = self.function_classifier.classify_function(
                func, file_path, 'python'
            )
            classifications.append({
                'file_path': file_path,
                'function_name': func['name'],
                'line_number': func.get('line_number', 0),
                'function_type': classification.function_type,
                'scope': classification.scope,
                'confidence': classification.confidence,
                'features': classification.features,
                'metadata': classification.metadata
            })
        
        return classifications
    
    def _enhance_tree_with_cross_file_info(self, call_tree: Dict[str, Any], 
                                          dependency_info: Dict[str, Any]) -> Dict[str, Any]:
        """Enhance call tree with cross-file dependency information."""
        # This is a placeholder for tree enhancement logic
        # In a full implementation, this would merge call graph data with cross-file resolution
        enhanced_tree = call_tree.copy()
        enhanced_tree['cross_file_info'] = dependency_info
        return enhanced_tree
    
    def _flatten_tree_nodes(self, tree: Dict[str, Any]) -> List[Dict[str, Any]]:
        """Flatten tree nodes for analysis."""
        # Simple implementation - would be more sophisticated in practice
        nodes = []
        if 'root' in tree:
            nodes.append(tree['root'])
        if 'children' in tree:
            for child in tree['children']:
                nodes.extend(self._flatten_tree_nodes(child))
        return nodes
    
    def get_supported_extensions(self) -> List[str]:
        """Return list of supported file extensions."""
        return ['.py', '.pyi', '.pyx']
    
    def get_language_info(self) -> Dict[str, Any]:
        """Return information about Python language support."""
        return {
            'language': 'python',
            'version_support': '3.8+',
            'features': [
                'AST parsing',
                'Function call detection',
                'Import resolution',
                'Class hierarchy analysis',
                'Decorator analysis',
                'Type hint analysis',
                'Dynamic call detection'
            ],
            'limitations': [
                'Dynamic imports may not be fully resolved',
                'eval/exec calls cannot be statically analyzed',
                'Some metaclass behaviors are not tracked'
            ]
        }